//////////////////////////////////////////////////////////////////////////
//	File	:	"SGD_Math.cpp"
//
//	Author	:	David Brown (DB)
//
//	Purpose	:	To do lots of math for us.
///////////////////////////////////////////////////////////////////////////
#include "SGD_Math.h"

//#include "../Managers/MapManager.h"

#include <Windows.h>
#include <float.h>	//	for fabs() and _isnan()
#include <math.h>	//	for sqrt()
#include <vector>
#include <ctime>

using namespace std;


Vector2D::Vector2D()
{
	fX = 0;
	fY = 0;
}

Vector2D::Vector2D(float m_fX,float m_fY)
{
	fX = m_fX;
	fY = m_fY;
}

Vector2D Vector2D::operator+(const Vector2D& v)
{
	Vector2D ret;
	ret.fX = fX + v.fX;
	ret.fY = fY + v.fY;

	return ret;
}
Vector2D Vector2D::operator-(const Vector2D& v)
{
	Vector2D ret;
	ret.fX = fX - v.fX;
	ret.fY = fY  - v.fY;

	return ret;
}
Vector2D Vector2D::operator*(const float f)
{
	Vector2D ret;
	ret.fX =	fX * f;
	ret.fY =	fY * f;
	return ret;
}
Vector2D Vector2D::operator/(const float f)
{
	Vector2D ret;
	if(f != 0.00)
	{
		ret.fX = fX/f;
		ret.fY = fY/f;
	}
	else
	{
		ret.fX = fX;
		ret.fY = fY;
	}

	return ret;
}

int RandInt( int RangeLow, int RangeHigh)
{
	srand( unsigned int(time(0)));

	int RandomNum = rand() % ((RangeHigh - RangeLow) + 1 );
	return RandomNum;
}

float absolute(float value)
{
	if(value >= 0)
		return value;
	else
		return -(value);
}

bool IsEven(int Num)
{

	if( (Num & 1) == 0 )
	{
		return true;
	}

	return false;
}

float Vector2D::LengthOfVector(Vector2D vec)
{
	float Length = sqrt( (vec.fX * vec.fX) + (vec.fY * vec.fY));
	return Length;
}

//	Find the length of a vector (magnitude)
float Vector2DLength(Vector2D vec)
{
	//	A^2 + B^2 = C^2
	//	C = sqrt(A^2 + B^2)
	return sqrt( (vec.fX * vec.fX) + (vec.fY * vec.fY) );
}

// Find the dot product
float DotProduct(Vector2D v1, Vector2D v2)
{
	//	(a.x * b.x) + (a.y * b.y)
	return (v1.fX * v2.fX) + (v1.fY * v2.fY);
}

//	Normalize a vector
Vector2D Vector2DNormalize(Vector2D vec)
{
	float fLength = Vector2DLength(vec);

	Vector2D vNormalized = vec / fLength;

	//	Return the normalized vector
	return vNormalized;
}

//	Rotate a vector
/*
	X, Y	=	[X]
				[Y]
				[1]

	[	cos&	sin&	0	]		[X]		[X1]
	[  -sin&	cos&	0	]	*	[Y]	=	[Y1]
	[	0		0		1	]		[1]		[1]
*/
Vector2D Vector2DRotate(Vector2D vec, float fRadians)
{
	//	Convert into the Cartesian coordinate system
	vec.fY *= -1.0f;

	Vector2D vRotated;
	vRotated.fX = (cos(fRadians) * vec.fX) + (sin(fRadians) * vec.fY);
	vRotated.fY = (-sin(fRadians) * vec.fX) + (cos(fRadians) * vec.fY);

	//	Convert back to our windows coordinate system
	vRotated.fY *= -1.0f;

	//	Return our rotated vector
	return vRotated;
}

//	Find the angle between 2 vectors
float AngleBetweenVectors(Vector2D v1, Vector2D v2)
{
	//	Dot product
	float fDot = DotProduct(v1, v2);

	//	Length of those vectors
	float fLength =  Vector2DLength(v1) * Vector2DLength(v2);

	//	Make sure we don't get a divide by zero error.
	if (fLength == 0.0f)	return 0.0f;

	//	Calculate the angle between the two vectors
	float fAngle = acos( fDot / fLength );

	//	Make sure the number is not indefinite.  Shows up as -1.#IND00000.  Not a number.
	if (_isnan(fAngle))
		return 0.0f;

	//	Return the angle.
	return fAngle;
}

//	Linear Interpolation
//	v = a + ((b - a) * t)
float Lerp(float fStart, float fEnd, float fPercent)
{
	return fStart + ((fEnd - fStart) * fPercent);
}

//	Tests if two floats are approximately equal given a margin of error
bool FloatEquals(float fResult, float fExpected, float fEpsilon)
{
	return (fabs(fResult - fExpected) < fEpsilon);
}

//	Determines which way to turn (clockwise or counter-clockwise)
float Steering(Vector2D vOrientation, Vector2D vToTarget)
{
	//	Uses the Z-component of the cross product
	return (vOrientation.fX * vToTarget.fY) - (vOrientation.fY * vToTarget.fX);
}

float Round(float number)
{
	return (number > 0.0) ? (float)floor(number + 0.5) : (float)ceil(number - 0.5);
}

bool IntersectCircle(const Vector2D& first, const float& firstradius, const Vector2D& second, const float& secondradius)
{
	float dx = second.fX - first.fX;
	float dy = second.fY - first.fY;
	float radius = firstradius + secondradius;

	if((dx * dx) + (dy * dy) < (radius * radius))
	{
		return true;
	}

	return false;
}
//
//bool IntersectLineOfSight(Vector2D start, Vector2D end, float checkradius)
//{
//	vector<RECT*>* collideMaster = MapManager::GetInstance()->GetCollidableTiles();
//	vector<RECT*> collide;
//
//	HRGN region = CreateEllipticRgn((int)(start.fX - checkradius), (int)(start.fY - checkradius),
//									(int)(start.fX + checkradius), (int)(start.fY + checkradius));
//
//	for(unsigned i = 0; i < collideMaster->size(); ++i)
//	{
//		if(RectInRegion(region, (*collideMaster)[i]))
//		{
//			collide.push_back((*collideMaster)[i]);
//		}
//	}
//
//	DeleteObject(region);
//
//	POINT checkpoint;
//
//	tVector2D direction;
//	direction.fX = 0.0f;
//	direction.fY = -1.0f;
//
//	tVector2D angleposition;
//	angleposition = end - start;
//
//	float rotation = AngleBetweenVectors(angleposition, direction);
//
//	if(angleposition.fX < 0.0f)
//		rotation = -rotation;
//
//	direction = Vector2DRotate(direction, rotation);
//
//	direction = direction * 5;
//
//	float velx = direction.fX;
//	float vely = direction.fY;
//
//	if((direction.fX < 0.1f && direction.fX > -0.1f) || (direction.fY < 0.1f && direction.fY > -0.1f))
//		return true;
//
//	if(_isnan(direction.fX) || _isnan(direction.fY))
//		return true;
//
//	if(start.fX > end.fX && start.fY > end.fY)
//	{
//		while(start.fX > end.fX || start.fY > end.fY)
//		{
//			checkpoint.x = (int)start.fX;
//			checkpoint.y = (int)start.fY;
//
//			for(unsigned i = 0; i < collide.size(); ++i)
//			{
//				if(PtInRect(collide[i], checkpoint))
//				{
//					return true;
//				}
//			}
//
//			start.fX += direction.fX;
//			start.fY += direction.fY;
//		}
//	}
//	else if(start.fX > end.fX && start.fY < end.fY)
//	{
//		while(start.fX > end.fX || start.fY < end.fY)
//		{
//			checkpoint.x = (int)start.fX;
//			checkpoint.y = (int)start.fY;
//
//			for(unsigned i = 0; i < collide.size(); ++i)
//			{
//				if(PtInRect(collide[i], checkpoint))
//				{
//					return true;
//				}
//			}
//
//			start.fX += direction.fX;
//			start.fY += direction.fY;
//		}
//	}
//	else if(start.fX < end.fX && start.fY > end.fY)
//	{
//		while(start.fX < end.fX || start.fY > end.fY)
//		{
//			checkpoint.x = (int)start.fX;
//			checkpoint.y = (int)start.fY;
//
//			for(unsigned i = 0; i < collide.size(); ++i)
//			{
//				if(PtInRect(collide[i], checkpoint))
//				{
//					return true;
//				}
//			}
//
//			start.fX += direction.fX;
//			start.fY += direction.fY;
//		}
//	}
//	else if(start.fX < end.fX && start.fY < end.fY)
//	{
//		while(start.fX < end.fX || start.fY < end.fY)
//		{
//			checkpoint.x = (int)start.fX;
//			checkpoint.y = (int)start.fY;
//
//			for(unsigned i = 0; i < collide.size(); ++i)
//			{
//				if(PtInRect(collide[i], checkpoint))
//				{
//					return true;
//				}
//			}
//
//			start.fX += direction.fX;
//			start.fY += direction.fY;
//		}
//	}
//
//	return false;
//}
//
//bool IntersectFlashlight(Vector2D enemy, Vector2D player, float radius, float currentrotation, float checkangle)
//{
//	Vector2D flashlight;
//	flashlight.fX = 0.0f;
//	flashlight.fY = -1.0f;
//
//	Vector2D playervector;
//	playervector.fX = 0.0f;
//	playervector.fY = -1.0f;
//
//	HRGN region = CreateEllipticRgn((int)(enemy.fX - radius), (int)(enemy.fY - radius),
//									(int)(enemy.fX + radius), (int)(enemy.fY + radius));
//
//	if(!PtInRegion(region, (int)player.fX, (int)player.fY))
//	{
//		DeleteObject(region);
//		return false;
//	}
//
//	DeleteObject(region);
//
//	flashlight = Vector2DRotate(flashlight, currentrotation);
//
//	Vector2D angleposition;
//	angleposition = player - enemy;
//
//	float rotation = AngleBetweenVectors(angleposition, playervector);
//
//	if(angleposition.fX < 0.0f)
//		rotation = -rotation;
//
//	playervector = Vector2DRotate(playervector, rotation);
//
//	if(AngleBetweenVectors(flashlight, playervector) < (checkangle * (SGD_PI / 180)))
//	{
//		return true;
//	}
//
//	return false;
//}